﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

namespace DDD {
    /// <summary>
    /// <see cref="Sampler"/>クラスに拡張メソッドを追加するクラス
    /// </summary>
    public static class SamplerExtensions {

        /// <summary>
        /// コンパイル
        /// </summary>
        /// <remarks>
        /// テクスチャーに画像がセットされていない場合例外が発生する事があります。
        /// </remarks>
        /// <param name="sam"><see cref="Sampler"/>オブジェクト</param>
        public static void Compile (this Sampler sam) {
            var img = sam.Image;
            if (img != null) {
                img.Compile ();
            }

            var cache = Graphics3DExtensions.GetGLCache ();
            var id = cache[sam];
            if (id > 0) {
                return;
            }

            ErrorCode err;

            GL.GenSamplers (1, out id);
            if ((err = GL.GetError ()) > 0) {
                throw new InvalidOperationException ("glGenSamplers was failed, err=" + err);
            }

            var image = sam.ImageFilter;
            var level = sam.LevelFilter;

            if (image == ImageFilter.Nearest && level == LevelFilter.Base) {
                GL.SamplerParameter (id, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Nearest);
                GL.SamplerParameter (id, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.Nearest);
            }
            if (image == ImageFilter.Linear && level == LevelFilter.Base) {
                GL.SamplerParameter (id, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Linear);
                GL.SamplerParameter (id, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.Linear);
            }
            if (image == ImageFilter.Nearest && level == LevelFilter.Nearest) {
                GL.SamplerParameter (id, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Nearest);
                GL.SamplerParameter (id, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.NearestMipmapNearest);
            }
            if (image == ImageFilter.Nearest && level == LevelFilter.Linear) {
                GL.SamplerParameter (id, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Nearest);
                GL.SamplerParameter (id, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.NearestMipmapLinear);
            }
            if (image == ImageFilter.Linear && level == LevelFilter.Nearest) {
                GL.SamplerParameter (id, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Linear);
                GL.SamplerParameter (id, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.LinearMipmapNearest);
            }
            if (image == ImageFilter.Linear && level == LevelFilter.Linear) {
                GL.SamplerParameter (id, SamplerParameter.TextureMagFilter, (int)TextureMagFilter.Linear);
                GL.SamplerParameter (id, SamplerParameter.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
            }
            if ((err = GL.GetError ()) > 0) {
                throw new InvalidOperationException ("glSamplerParameter(Filter) was failed, err=" + err);
            }

            GL.SamplerParameter (id, SamplerParameter.TextureWrapR, (int)sam.WrapMode.ToGL ());
            GL.SamplerParameter (id, SamplerParameter.TextureWrapS, (int)sam.WrapMode.ToGL ());
            GL.SamplerParameter (id, SamplerParameter.TextureWrapT, (int)sam.WrapMode.ToGL ());
            if ((err = GL.GetError ()) > 0) {
                throw new InvalidOperationException ("glSamplerParameter(WrapMode) was failed, err=" + err);
            }

            cache.Add (sam, id);
        }


        /// <summary>
        /// サンプラーのレンダリング
        /// </summary>
        /// <remarks>
        /// サンプラーに画像がセットされていない場合例外が発生する事があります。
        /// </remarks>
        /// <param name="sam"><see cref="Sampler"/>オブジェクト</param>
        /// <param name="unit">テクスチャーユニット番号</param>
        public static void Render (this Sampler sam, int unit) {
            var cache = Graphics3DExtensions.GetGLCache ();
            var id = cache[sam];
            if (id == 0) {
                throw new InvalidOperationException ("OpenGL id was not found");
            }
            ErrorCode err;

            GL.ActiveTexture (TextureUnit.Texture0 + unit);
            if ((err = GL.GetError ()) > 0) {
                throw new ArgumentException ("glActiveTexture was failed, err=" + err);
            }

            foreach (var img in sam.Images) {
                img.Render ();
            }

            GL.BindSampler (unit, id);
            
            /*
            GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapR, (int)OpenTK.Graphics.OpenGL.TextureWrapMode.Repeat);
            GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)OpenTK.Graphics.OpenGL.TextureWrapMode.Repeat);
            GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)OpenTK.Graphics.OpenGL.TextureWrapMode.Repeat);
            GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)OpenTK.Graphics.OpenGL.TextureMagFilter.Linear);
            GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)OpenTK.Graphics.OpenGL.TextureMinFilter.Linear);

            GL.BindSampler (unit, 0);
            */
        }

    }
}
